home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / SAT 2.4.0 / SAT / Add-ons / Load faces / FastLoad.p < prev   
Encoding:
Text File  |  1997-01-28  |  16.1 KB  |  437 lines  |  [TEXT/PJMM]

  1. unit FastLoad;
  2.  
  3. {This unit holds routines for loading faces pointing into parts of offscreen buffers. This is useful for}
  4. {loading large numbers of faces really fast (since it is drawn in one operation, and much fewer Memory}
  5. {Management and Resource Manager operations are needed), but also for odd sprites that "peek" into}
  6. {other parts of offscreens.}
  7.  
  8. {The call Load2DFaceArray is the most interesting one. It loads one PICT resource to a large number}
  9. {of faces (hundreds) in a fraction of a second.}
  10.  
  11. {/Ingemar Ragnemalm december 1995}
  12. {Revised may 1996}
  13. {Revised again august 1996}
  14. {(Revisions above fix some hard-coded values, adds row list support, and fixes bugs.)}
  15. {Revised once more november 1996. Port restored by LoadFaceArray/Load2DFaceArray.}
  16. {Outcommented code removed.}
  17. {Revised again jan 97: Now row lists work properly.}
  18.  
  19. interface
  20.     uses
  21. {$ifc UNDEFINED THINK_PASCAL}
  22.         Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
  23.         Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile,{}
  24.         GestaltEqu, Files, Errors, Devices, 
  25. {$endc}
  26.         SAT;
  27.  
  28.     type
  29.         FaceArr = array[0..1000] of Face;
  30.         FaceArrPtr = ^FaceArr;
  31.  
  32. {PeekFaceInOffscreen: A variation on BuildFaceInOffscreen, intended for special effects. It doesn't}
  33. {allocate the face data, but demands that the face already exists. Use it for making a sprite face}
  34. {peek into some image buffer other than its own private one.}
  35.     procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPortPtr; bounds: Rect;{}
  36.                                     needsRegion, makeRowList: Boolean);
  37.  
  38. {BuildFaceInOffscreen: This is the heart of FastLoad. It builds a face pointing into some image of}
  39. {your choice.}
  40.     procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect;{}
  41.                                     needsRegion, makeRowList: Boolean);
  42.  
  43. {LoadFaceArray and Load2DFaceArray: High-level functions, for loading faces arrange in arrays}
  44. {in PICTs.}
  45.     function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
  46.                                     needsRegion, makeRowList: Boolean): FaceArrPtr;
  47.     function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer;{}
  48.                                     facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
  49.  
  50. {Note: The two Booleans needsRegion and makeRowList, used in all routines above, tell whether you}
  51. {want certain extra data in the face. Set needsRegion to true if you want to run your program to run}
  52. {as fast as possible WITHOUT blitters, using only QuickDraw. Set makeRowList of you want it to run}
  53. {with optimal speed WITH blitters. If both are false, it will load extremely fast, but the animation may}
  54. {not run quite as fast.}
  55.  
  56. {This routine is in SAT.lib, but not in the interface files! It is for internal use by the unit.}
  57.     procedure SATMakeRowList (portRect: Rect; baseAddr: Ptr; rowBytes: integer; var rows: Ptr; depth: Integer);
  58.  
  59. implementation
  60.  
  61.  
  62.     type
  63.         BMPtr = ^BitMap;
  64.  
  65.         FourBitStuff = record
  66.                 evenData, oddData: Ptr;
  67.                 oddMask: BitMap;
  68.                 oddRowBytes: integer;
  69.                 destRect: Rect; {Behövs för safe}
  70.                 oddRows, oddMaskRows: Ptr;
  71.             end;
  72.         FourBitPtr = ^FourBitStuff;
  73.  
  74.  
  75. {BuildFaceInOffscreen builds a face that points into two offscreen imgaes, one for the image data}
  76. {and one for the mask. This can be used for loading faces quickly, but also for making weirds}
  77. {sprites who peek into other parts of the screen.}
  78. {}
  79. {This will probably NEVER get really good in 4-bit color.}
  80.  
  81.     procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect; needsRegion, makeRowList: Boolean);
  82.         var
  83.             b2: Rect;
  84.     begin
  85.         theFace.iconMask.baseAddr := Ptr(Longint(maskOff.baseAddr) + Longint(maskOff.rowBytes) * bounds.top + bounds.left div 8); {32 pixels wide = 4 bytes wide in B/W}
  86.         theFace.iconMask.rowBytes := maskOff.rowBytes;
  87.         theFace.iconMask.bounds := bounds;
  88.         OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
  89.         theFace.rowBytes := imageOff.rowBytes;
  90.  
  91.         b2 := bounds;
  92.         OffsetRect(b2, -b2.left, -b2.top);
  93.  
  94.         if gSAT.initDepth = 1 then
  95.             begin
  96.                 theFace.colorData := NewPtrClear(sizeOf(BitMap));
  97.                 if theFace.colorData <> nil then
  98.                     begin
  99.                         BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
  100.                         BMPtr(theFace.colorData)^.rowBytes := imageOff.rowBytes;
  101.                         BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left div 8);
  102.                         theFace.rows := nil;
  103.                         if makeRowList then
  104.                             SATMakeRowList(b2, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
  105.                     end;
  106.             end
  107.         else if gSAT.initDepth = 4 then
  108. {4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
  109. {since it is better than crashing.}
  110.             begin
  111.                 theFace.colorData := NewPtrClear(sizeof(FourBitStuff));
  112.  
  113.                 if theFace.colorData <> nil then
  114.                     with FourBitPtr(theFace.colorData)^ do
  115.                         begin
  116. {theFace.rowBytes := imageOff.rowBytes;}
  117.                             evenData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  118.                             theFace.rows := nil;
  119.                             if makeRowList then
  120.                                 SATMakeRowList(b2, evenData, theFace.rowBytes, theFace.rows, 4);
  121.  
  122.                             oddRowBytes := imageOff.rowBytes;
  123.                             oddData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  124.  
  125.                             destRect := theFace.iconMask.bounds;
  126.                             oddRows := nil;
  127.                             if makeRowList then
  128.                                 SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
  129.  
  130.                             BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
  131.  
  132.                             oddMaskRows := nil;
  133.                             if makeRowList then
  134.                                 SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
  135.                             theFace.maskRows := nil;
  136.                             if makeRowList then
  137.                                 SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  138.                         end;
  139.             end
  140.         else
  141.             begin
  142.                 theFace.colorData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  143.                 theFace.rows := nil;
  144.                 if makeRowList then
  145.                     SATMakeRowList(b2, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
  146.                 theFace.maskRows := nil;
  147.                 if makeRowList then
  148.                     SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  149.             end;
  150.  
  151.         theFace.next := nil;
  152.  
  153. {Build region. This is time consuming, but can be skipped. Without them, drawing without blitters can slow down a bit.}
  154. {Another option is to use one region for several masks, when we know some masks are equal.}
  155.         if needsRegion then
  156.             begin
  157.                 theFace.maskRgn := NewRgn;
  158.                 if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
  159.                     ;
  160.             end
  161.         else
  162.             theFace.maskRgn := nil;
  163.  
  164. {Hooks that we don't use here:}
  165.         theFace.redrawProc := nil;
  166.         theFace.drawProc := nil;
  167.     end; {BuildFaceInOffscreen}
  168.  
  169.  
  170. {PeekFaceInOffscreen is very similar to BuildFaceInOffscreen, but doesn't build the face, but just changes its}
  171. {pointers to another place in the offscreens, in order to change where it points. You can then have it pointing}
  172. {anywhere, into other ports, to the screen etc. However, if the memory it points to changes, sprites using}
  173. {the face have to set their "dirty" flag in order to work with SATRun2 unless they move all the time!}
  174.  
  175. {The differences to BuildFaceInOffscreen are that}
  176. {- it doesn't allocate pointers, nor initialize any parts of the face. The face is assumed to be in use already.}
  177. {- the SATPorts are passed as pointers, and may be nil. If one of them is nil, that part of the procedure will}
  178. {not be run. That lets you keep the mask and change the image.}
  179.  
  180. {Note: This hasn't been tested a lot since the last update.}
  181.  
  182.     procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPortPtr; bounds: Rect; needsRegion, makeRowList: Boolean);
  183.         var
  184.             b2: Rect;
  185.     begin
  186.         if maskOff <> nil then
  187.             begin
  188.                 theFace.iconMask.baseAddr := Ptr(Longint(maskOff^.baseAddr) + Longint(maskOff^.rowBytes) * bounds.top + bounds.left div 8); {32 pixels wide = 4 bytes wide in B/W}
  189.                 theFace.iconMask.rowBytes := maskOff^.rowBytes;
  190.                 theFace.iconMask.bounds := bounds;
  191.                 OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
  192.             end;
  193.  
  194.         if imageOff <> nil then
  195.             begin
  196.                 theFace.rowBytes := imageOff^.rowBytes;
  197.                 b2 := bounds;
  198.                 OffsetRect(b2, -b2.left, -b2.top);
  199.  
  200.                 if gSAT.initDepth = 1 then
  201.                     begin
  202.                         if theFace.colorData <> nil then
  203.                             begin
  204.                                 BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
  205.                                 BMPtr(theFace.colorData)^.rowBytes := imageOff^.rowBytes;
  206.                                 BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left div 8);
  207.                                 theFace.rows := nil;
  208.                                 if makeRowList then
  209.                                     SATMakeRowList(b2, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
  210.                             end;
  211.                     end
  212.                 else if gSAT.initDepth = 4 then
  213. {4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
  214. {since it is better than crashing.}
  215.                     begin
  216.                         if theFace.colorData <> nil then
  217.                             with FourBitPtr(theFace.colorData)^ do
  218.                                 begin
  219.                                     theFace.rowBytes := imageOff^.rowBytes;
  220.                                     evenData := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  221.                                     theFace.rows := nil;
  222.                                     if makeRowList then
  223.                                         SATMakeRowList(b2, evenData, theFace.rowBytes, theFace.rows, 4);
  224.  
  225.                                     oddRowBytes := imageOff^.rowBytes;
  226.                                     oddData := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  227.  
  228.                                     destRect := theFace.iconMask.bounds;
  229.                                     oddRows := nil;
  230.                                     if makeRowList then
  231.                                         SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
  232.  
  233.                                     BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
  234.  
  235.                                     oddMaskRows := nil;
  236.                                     if makeRowList then
  237.                                         SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
  238.                                     theFace.maskRows := nil;
  239.                                     if makeRowList then
  240.                                         SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  241.                                 end;
  242.                     end
  243.                 else
  244.                     begin
  245.                         theFace.colorData := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  246.                         theFace.rows := nil;
  247.                         if makeRowList then
  248.                             SATMakeRowList(b2, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
  249.                         theFace.maskRows := nil;
  250.                         if makeRowList then
  251.                             SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  252.                     end;
  253.  
  254. {theFace.rowBytes := imageOff^.rowBytes;}
  255.             end;
  256.  
  257. {Build region. This is time consuming, but can be skipped if we only draw with blitters - but that means}
  258. {giving up the safety backdoor! Another option is to use on region for several masks, when we know}
  259. {some masks are equal.}
  260.         if needsRegion then
  261.             begin
  262.                 if theFace.maskRgn = nil then
  263.                     theFace.maskRgn := NewRgn;
  264.                 if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
  265.                     ;
  266.             end
  267.         else
  268.             ;
  269.     end; {PeekFaceInOffscreen}
  270.  
  271.  
  272. {CreateBWOffscreen is useful for creating a B/W offscreeen buffer for masks}
  273.  
  274.     procedure CreateBWOffscreen (var portP: SATPort; frame: Rect);
  275.         var
  276.             savePort: GrafPtr;
  277.     begin
  278.         GetPort(savePort);
  279.  
  280.         portP.device := nil;
  281.         portP.port := GrafPtr(NewPtr(sizeof(GrafPort)));
  282.         CheckNoMem(Ptr(portP.port));                        {Emergency exit}
  283.  
  284.         OpenPort(portP.port);
  285.         portP.port^.portRect := frame;
  286.         portP.port^.portBits.bounds := portP.port^.portRect;
  287.  
  288.         RectRgn(portP.port^.visRgn, frame);
  289.         ClipRect(frame);
  290.  
  291.         portP.port^.portBits.rowBytes := longint(((portP.port^.portRect.right - portP.port^.portRect.left + 31) div 32) * 4);
  292.         portP.port^.portBits.baseAddr := NewPtr(portP.port^.portBits.rowBytes * longint(portP.port^.portRect.bottom - portP.port^.portRect.top));
  293.         CheckNoMem(portP.port^.portBits.baseAddr); {Emergency exit}
  294.  
  295.         SetPort(portP.port);
  296.         EraseRect(portP.port^.portRect);
  297.  
  298.         portP.baseAddr := portP.port^.portBits.baseAddr;
  299.         portP.bounds := portP.port^.portBits.bounds;
  300.         portP.rowBytes := portP.port^.portBits.rowBytes;
  301.  
  302. {portP.rows:=nil;}
  303. {with portP.port^ do}
  304. {SATMakeRowList(portRect, portBits.baseAddr, portBits.rowBytes, portP.rows, 1);}
  305.  
  306.         SetPort(savePort);
  307.     end; {CreateBWOffscreen}
  308.  
  309. {LoadFaceArray loads a set of faces to a one-dimensional array of faces, arranged vertically in a PICT}
  310. {resource. It is extended to 2-dimensional arrays by Load2DFaceArray below. NOT TESTED MUCH!}
  311.     function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
  312.                                     needsRegion, makeRowList: Boolean): FaceArrPtr;
  313.         var
  314.             fr, mr: Rect;
  315.             savePort, facesOff, masksOff: SATPort;
  316.             i: Integer;
  317.             faces: FaceArrPtr;
  318.             facesPict, masksPict: PicHandle;
  319.             bounds: Rect;
  320.     begin
  321.         SATGetPort(savePort);
  322.  
  323.         LoadFaceArray := nil;
  324.         faces := FaceArrPtr(NewPtr(SizeOf(Face) * numFaces));
  325.         if faces = nil then
  326.             Exit(LoadFaceArray);
  327.  
  328.         facesPict := GetPicture(facesPictId);
  329.         if facesPict = nil then
  330.             begin
  331.                 DisposePtr(Ptr(faces));
  332.                 Exit(LoadFaceArray);
  333.             end;
  334.         masksPict := GetPicture(masksPictId);
  335.         if masksPict = nil then
  336.             begin
  337.                 ReleaseResource(Handle(facesPict));
  338.                 DisposePtr(Ptr(faces));
  339.                 Exit(LoadFaceArray);
  340.             end;
  341.  
  342.         fr := facesPict^^.picFrame;
  343.         OffsetRect(fr, -fr.left, -fr.top);
  344.  
  345.         SATMakeOffscreen(facesOff, fr);
  346.         SATSetPort(facesOff);
  347.         DrawPicture(facesPict, fr);
  348.  
  349.         mr := masksPict^^.picFrame;
  350.         OffsetRect(mr, -mr.left, -mr.top);
  351.  
  352.         CreateBWOffscreen(masksOff, mr);
  353.         SATSetPort(masksOff);
  354.         DrawPicture(masksPict, mr);
  355.  
  356.         ReleaseResource(Handle(facesPict));
  357.         ReleaseResource(Handle(masksPict));
  358.  
  359. {This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures!}
  360.  
  361.         for i := 0 to numFaces - 1 do
  362.             begin
  363.                 SetRect(bounds, 0, i * sizeV, sizeH, (i + 1) * sizeV);
  364.                 BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
  365.             end;
  366.  
  367.         LoadFaceArray := faces;
  368.         SATSetPort(savePort);
  369.     end; {LoadFaceArray}
  370.  
  371.  
  372. {Load2DFaceArray loads a set of faces to a two-dimensional array of faces, arranged as a grid in a PICT}
  373. {resource. IMPORTANT! All faces must have a width divisible by 8, or better, 16 or even 32!}
  374.     function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
  375.                                     facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
  376.         var
  377.             fr, mr: Rect;
  378.             savePort, facesOff, masksOff: SATPort;
  379.             i, h, v: Integer;
  380.             faces: FaceArrPtr;
  381.             facesPict, masksPict: PicHandle;
  382.             bounds: Rect;
  383.     begin
  384.         SATGetPort(savePort);
  385.  
  386.         Load2DFaceArray := nil;
  387.         faces := FaceArrPtr(NewPtr(SizeOf(Face) * numFaces));
  388.         if faces = nil then
  389.             Exit(Load2DFaceArray);
  390.  
  391.         facesPict := GetPicture(facesPictId);
  392.         if facesPict = nil then
  393.             begin
  394.                 DisposePtr(Ptr(faces));
  395.                 Exit(Load2DFaceArray);
  396.             end;
  397.         masksPict := GetPicture(masksPictID);
  398.         if masksPict = nil then
  399.             begin
  400.                 ReleaseResource(Handle(facesPict));
  401.                 DisposePtr(Ptr(faces));
  402.                 Exit(Load2DFaceArray);
  403.             end;
  404.  
  405.         fr := facesPict^^.picFrame;
  406.         OffsetRect(fr, -fr.left, -fr.top);
  407.  
  408.         SATMakeOffscreen(facesOff, fr);
  409.         SATSetPort(facesOff);
  410.         DrawPicture(facesPict, fr);
  411.  
  412.         mr := masksPict^^.picFrame;
  413.         OffsetRect(mr, -mr.left, -mr.top);
  414.  
  415.         CreateBWOffscreen(masksOff, mr);
  416.         SATSetPort(masksOff);
  417.         DrawPicture(masksPict, mr);
  418.  
  419.         ReleaseResource(Handle(facesPict));
  420.         ReleaseResource(Handle(masksPict));
  421.  
  422. {This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures,}
  423. {arranged with facesPerRow faces per row!}
  424.  
  425.         for i := 0 to numFaces - 1 do
  426.             begin
  427.                 h := i mod facesPerRow;    {0..facesPerRow-1}
  428.                 v := i div facesPerRow;        {0 and up}
  429.                 SetRect(bounds, h * sizeH, v * sizeV, (h + 1) * sizeH, (v + 1) * sizeV);
  430.                 BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
  431.             end;
  432.  
  433.         Load2DFaceArray := faces;
  434.         SATSetPort(savePort);
  435.     end; {Load2DFaceArray}
  436.  
  437. end.